package common.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.db.Entity;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yuntsg.nnsfcp.common.utils.RedisUtil;
import com.yuntsg.ruiijn.databse_search.entity.FileDetails;
import com.yuntsg.ruiijn.databse_search.entity.ResultQueue;
import com.yuntsg.ruiijn.databse_search.mapper.FileDetailsMapper;
import com.yuntsg.ruiijn.databse_search.service.FeatureService;
import com.yuntsg.ruiijn.databse_search.service.ResultQueueService;
import common.sysconfig.RabbitmqConfig;
import common.vo.ComparisonRes;
import common.vo.ContentsComparisonRes;
import common.vo.JpgInfo;
import common.vo.PictureWireVo;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.features2d.Features2d;
import org.opencv.features2d.FlannBasedMatcher;
import org.opencv.features2d.SIFT;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.util.List;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@SuppressWarnings("all")
@Component
@Slf4j
public class ImageComparison {

    @Value("${upload.tempPath}")
    public String tempPath;
    @Resource
    private RedisUtil redisUtil;
    @Autowired
    private FeatureService featureService;
    @Autowired
    private MinioUtil minioUtil;
    @Autowired
    private SortUtil sortUtil;
    @Autowired
    private FileDetailsMapper fileDetailsMapper;
    @Autowired
    private ResultQueueService resultQueueService;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public static int getState(List<ImgAndScore> imgAndScoreList, int type) {
        int sum = 0;
        for (ImgAndScore imgAndScore : imgAndScoreList) {
            if (imgAndScore.getState() == type) {
                sum++;
            }
        }
        return sum;
    }

    public static Map<Integer, Float> mapSortByValue(Map<Integer, Float> map) {
        Map<Integer, Float> result = new LinkedHashMap<>(map.size());
        map.entrySet().stream().sorted(Map.Entry.<Integer, Float>comparingByValue().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    public static String getStrField(Entity entry, String field) {
        if (null != entry) {
            String str = entry.getStr(field);
            if (null != str && str.length() > 0 && !str.toLowerCase().trim().equals("null")) {
                return str.trim();
            }
        }
        return "";
    }

    public static Boolean checkBlackImg(String filename) {
        Integer blackPointSize = 0;
        BufferedImage bi = ImgUtil.toBufferedImage(ImgUtil.read(filename));
        int height = bi.getHeight();
        int width = bi.getWidth();
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int rgb = bi.getRGB(j, i);
                Color color = ImgUtil.getColor(rgb);
                if (color.getRed() == 0 && color.getBlue() == 0 && color.getGreen() == 0) {
                    blackPointSize++;
                }
            }
        }
        if (blackPointSize / Convert.toDouble(width * height) > 0.9) {
            return true;
        } else {
            return false;
        }
    }

    public static List<ContentsComparisonRes> getJpgSortShow(List<FileDetails> aJpgList, List<FileDetails> bJpgList, Map<List<String>, JpgInfo> jpgInfoMap, boolean type) {
        Map<Integer, FileDetails> adict = aJpgList.stream().collect(Collectors.toMap(FileDetails::getId, FileDetails -> FileDetails, (key1, key2) -> key2));
        Map<Integer, FileDetails> bdict = bJpgList.stream().collect(Collectors.toMap(FileDetails::getId, FileDetails -> FileDetails, (key1, key2) -> key2));
        Map<String, Double> jpgMaxScoreMap = new HashMap<>(); // 各组中的图片综合相似度的最大值
        Map<String, Map<String, Double>> jpgListScoreMap = new HashMap<>(); // 各组中的各组内的图片综合相似度

        for (FileDetails aJpg : aJpgList) {
            double aJpgMax = 0.0;
            Map<String, Double> scoreMap = new HashMap<>(); // 各组中的图片的最大值
            for (FileDetails bJpg : bJpgList) {
                if (!aJpg.getId().equals(bJpg.getId())) {
                    List<String> jpgList = new ArrayList<>();
                    jpgList.add(aJpg.getId().toString());
                    jpgList.add(bJpg.getId().toString());
                    Collections.sort(jpgList);
                    double allScore = 0.0;
                    if (jpgInfoMap.containsKey(jpgList)) {
                        JpgInfo imgInfo = jpgInfoMap.get(jpgList);
                        // 原图为a，目标图为b
                        Boolean aIsWhite = imgInfo.getAIsWhite(); // 图A是否含有白块，true是含有，存在表中是1 a_is_white
                        Boolean bIsWhite = imgInfo.getBIsWhite(); // 图B是否含有白块，true是含有，存在表中是1 b_is_white
                        Boolean hasPic = imgInfo.getHasPic(); // 两张图之间是否有连线，true是有连线，存在表中是1，表字段is_line
                        Double badInBest1 = imgInfo.getBadInBest1(); // 通过过滤原图/目标图相邻线之间对角线距离比值计算出的坏线数量占总线数量比例 越小分越好 最大是0，最小是1
                        Double aHeight = imgInfo.getSourceRoundImgInfo().getHeightRatio();
                        Double aWidth = imgInfo.getSourceRoundImgInfo().getWidthRatio();
                        Double bHeight = imgInfo.getDesRoundImgInfo().getHeightRatio();
                        Double bWidth = imgInfo.getDesRoundImgInfo().getWidthRatio();
                        double height; // 原图圈定区域比值 a - b 小的除以大的，最高得分是1，最低是0
                        if (aHeight == 0 && bHeight == 0) {
                            height = 0;
                        } else {
                            height = aHeight > bHeight ? bHeight / aHeight : aHeight / bHeight;
                        }
                        double width; // 目标图圈定区域比值 a - b 小的除以大的，最高得分是1，最低是0

                        if (aWidth == 0 && bWidth == 0) {
                            width = 0;
                        } else {
                            width = aWidth > bWidth ? bWidth / aWidth : aWidth / bWidth;
                        }
                        Double lineRoundRate = imgInfo.getLineRoundRate(); // 原图/目标图对角线长度比值 越接近1分越好 最大是1，最小是0
                        float inScore = imgInfo.getInScore(); // A图框内图与B图框内图之间向量的相似度，最大是1
                        float score = imgInfo.getScore(); // 图A与图B之间向量的相似度，最大是1

                        allScore = aIsWhite ? allScore : allScore + 0.05; // 是否有白块0.05
                        allScore = bIsWhite ? allScore : allScore + 0.05; // 是否有白块0.05
                        allScore = hasPic ? (allScore + 0.05) : allScore; // 是否有连线0.05
                        double badInBestScore = ((badInBest1 - 1) * 0.15 + (0 - badInBest1) * 0.0015) / (0 - 1); // 坏线比0.15
                        double heightScore = ((height - 0) * 0.07 + (1 - height) * 0.0007) / (1 - 0); // 高占比0.07
                        double widthScore = ((width - 0) * 0.07 + (1 - width) * 0.0007) / (1 - 0); // 宽占比0.07
                        double inScoreScore = ((inScore - 0) * 0.3 + (1 - inScore) * 0.003) / (1 - 0); // 框内相似度0.3
                        double scoreScore = ((score - 0) * 0.15 + (1 - score) * 0.0015) / (1 - 0); // 大图相似度0.15
                        double lineRoundRateScore = ((lineRoundRate - 0) * 0.11 + (1 - lineRoundRate) * 0.0011) / (1 - 0); // 对角线0.11
//                        allScore += badInBestScore + heightScore + widthScore + inScoreScore + scoreScore + lineRoundRateScore;
                        allScore = score;

                    }
                    scoreMap.put(bJpg.getId().toString(), allScore);
                    aJpgMax = Math.max(allScore, aJpgMax);
                }
            }
            jpgListScoreMap.put(aJpg.getId().toString(), scoreMap);
            jpgMaxScoreMap.put(aJpg.getId().toString(), aJpgMax);
        }


        Map<String, Double> sortJpgMaxScoreMap = mapSortValue(jpgMaxScoreMap);
        Set<String> jpgZuHeSet = new HashSet<>();
        Map<String, List<OutputJpgInfo>> outputJpgInfoMap = new LinkedHashMap<>();
        for (Map.Entry<String, Double> entry : sortJpgMaxScoreMap.entrySet()) {
            String aJpg = entry.getKey();
            if (jpgListScoreMap.containsKey(aJpg)) {
                Map<String, Double> scoreMap = jpgListScoreMap.get(aJpg);
                Map<String, Double> sortScoreMap = mapSortValue(scoreMap);
                List<OutputJpgInfo> outputJpgInfoList = new ArrayList<>();
                for (Map.Entry<String, Double> entity : sortScoreMap.entrySet()) {
                    String bJpg = entity.getKey();
                    List<String> jpgList = new ArrayList<>();
                    OutputJpgInfo outputJpgInfo = new OutputJpgInfo();
                    outputJpgInfo.setJpg(bJpg);
                    jpgList.add(aJpg);
                    jpgList.add(bJpg);
                    Collections.sort(jpgList);
                    if (jpgInfoMap.containsKey(jpgList)) {
                        JpgInfo jpgInfo = jpgInfoMap.get(jpgList);
                        if (jpgInfo.getHasPic()) { // 两张图之间是否有连线，true是有连线
                            outputJpgInfo.setHasPic(1);
                        }
                    }
                    // 首次显示为1，再次显示是0
                    String zuHe = aJpg + "|" + bJpg;
                    if (!jpgZuHeSet.contains(zuHe)) {
                        jpgZuHeSet.add(zuHe);
                        jpgZuHeSet.add(bJpg + "|" + aJpg);
                        outputJpgInfo.setIsFirst(1);
                    }
                    outputJpgInfo.setScore(entity.getValue());
                    outputJpgInfoList.add(outputJpgInfo);
                }
                outputJpgInfoMap.put(aJpg, outputJpgInfoList);
            }
        }
        List<ContentsComparisonRes> contentsComparisonResList = new ArrayList<>();

        List<String> hasCompare = new ArrayList<>();
        for (String ajpg : outputJpgInfoMap.keySet()) {
            List<OutputJpgInfo> outputJpgInfos = outputJpgInfoMap.get(ajpg);
            ContentsComparisonRes contentsComparisonRes = new ContentsComparisonRes();
            contentsComparisonRes.setFileDetails(adict.get(Convert.toInt(ajpg)).setVector(null));
            contentsComparisonRes.setMax(outputJpgInfos.get(0).score);

            List<ComparisonRes> comparisonResList = new ArrayList<>();
            List<ComparisonRes> hasPicList = new ArrayList<>();

            for (OutputJpgInfo outputJpgInfo : outputJpgInfos) {
                int isFirst = outputJpgInfo.getIsFirst();
                if (isFirst != 1) {
                    continue;
                }


                ComparisonRes comparisonRes = new ComparisonRes();
                comparisonRes.setV(outputJpgInfo.getScore());
                comparisonRes.setFileDetails(bdict.get(Convert.toInt(outputJpgInfo.getJpg())).setVector(null));
                comparisonRes.setIsShow(outputJpgInfo.isFirst);
                int hasPic = outputJpgInfo.getHasPic();
                comparisonRes.setHasPic(hasPic == 1);
                if (hasPic == 1) {
                    List<String> jpgList = new ArrayList<>();
                    JpgInfo jpgInfo = new JpgInfo();
                    jpgList.add(ajpg);
                    jpgList.add(outputJpgInfo.getJpg());
                    Collections.sort(jpgList);
                    comparisonRes.setPicKey(jpgInfoMap.get(jpgList).getPic());
                    comparisonRes.setPicPath(jpgInfoMap.get(jpgList).getPic());
                    hasPicList.add(comparisonRes);
                }
                comparisonResList.add(comparisonRes);
            }
            contentsComparisonRes.setIsShow(hasPicList.size() > 0 ? 1 : 0);
            contentsComparisonRes.setList(comparisonResList);
            contentsComparisonRes.setHasPiclist(hasPicList);
            contentsComparisonResList.add(contentsComparisonRes);

        }

        return contentsComparisonResList;
    }

    public static Map<String, Double> mapSortValue(Map<String, Double> mapName) {
        Map<String, Double> result = new LinkedHashMap<>();
        mapName.entrySet().stream().sorted(Map.Entry.<String, Double>comparingByValue().reversed()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
        return result;
    }

    public static <T> List<List<T>> groupListByCount(List<T> list, int groupSize) {
        List<List<T>> result = new ArrayList<>();
        int size = list.size();

        for (int i = 0; i < size; i += groupSize) {
            int end = Math.min(size, i + groupSize);
            result.add(new ArrayList<>(list.subList(i, end)));
        }

        return result;
    }

    /**
     * 目录对比
     *
     * @param alist 目录A
     * @param blist 目录B
     * @param uid   用户id
     * @param type  key or path
     * @return
     */
    public List<ContentsComparisonRes> comparisonSort(List<FileDetails> alist, List<FileDetails> blist, Integer uid, boolean type, String contentsComparisonKey) {

        Map<List<String>, JpgInfo> jpgInfoMap = new ConcurrentHashMap<>();
        int present = 1;
        for (FileDetails aFile : alist) {
            blist.parallelStream().forEach(bFile -> {
                if (!aFile.getId().equals(bFile.getId())) {
                    String pathOrgin = aFile.getPath();
                    String pathTarget = bFile.getPath();
                    SortUtil.Result result1 = new SortUtil.Result();

                    List<String> jpgList = new ArrayList<>();
                    JpgInfo jpgInfo = new JpgInfo();
                    jpgList.add(aFile.getId().toString());
                    jpgInfo.setAJpg(aFile.getPath());
                    jpgList.add(bFile.getId().toString());
                    jpgInfo.setBJpg(bFile.getPath());
                    jpgInfo.setAIsWhite(aFile.getIsWhite());
                    jpgInfo.setBIsWhite(bFile.getIsWhite());
                    jpgInfo.setAVector(aFile.getVector());
                    jpgInfo.setBVector(bFile.getVector());
                    jpgInfo.setHasPic(false);
                    Collections.sort(jpgList);
                    float[] aFloats = ArrayUtils.toPrimitive(aFile.getVector().toArray(new Float[0]), 0.0F);
                    float[] bFloats = ArrayUtils.toPrimitive(bFile.getVector().toArray(new Float[0]), 0.0F);
                    jpgInfo.setScore(FeatureComparison.cosineSim(aFloats, bFloats)); // A图框内图与B图框内图之间向量的相似度
                    if (result1.getAllResult()) {

//                        String oPath = tempPath + RandomUtil.randomString(6) + ".png";
//                        String tPath = tempPath + RandomUtil.randomString(6) + ".png";
//
//
//                        SortUtil.RoundPoint sourceRoundPint = result1.getSourceRoundPint();
//                        SortUtil.RoundPoint desRoundPint = result1.getDesRoundPint();
//
//                        ImgUtil.cut(ImgUtil.read(new ByteArrayInputStream(minioUtil.downloadByte(pathOrgin))), new File(oPath), new Rectangle(sourceRoundPint.getMinX(), sourceRoundPint.getMinY(), sourceRoundPint.getMaxX() - sourceRoundPint.getMinX(), sourceRoundPint.getMaxY() - sourceRoundPint.getMinY()));
//                        ImgUtil.cut(ImgUtil.read(new ByteArrayInputStream(minioUtil.downloadByte(pathTarget))), new File(tPath), new Rectangle(desRoundPint.getMinX(), desRoundPint.getMinY(), desRoundPint.getMaxX() - desRoundPint.getMinX(), desRoundPint.getMaxY() - desRoundPint.getMinY()));
//
//                        List<Float> aInVector = featureService.imageFeature(oPath);
//                        List<Float> bInVector = featureService.imageFeature(tPath);
//
//                        FileUtil.del(oPath);
//                        FileUtil.del(tPath);

                        jpgInfo.setHasPic(true);
//                        jpgInfo.setAInVector(aInVector); // A图框内图的向量
//                        jpgInfo.setBInVector(bInVector); // B图框内图的向量

                        jpgInfo.setPicKey(result1.getResultImg());
                        jpgInfo.setPic(result1.getResultImg());


                        jpgInfo.setSourceRoundImgInfo(result1.getSourceRoundImgInfo()); // A图框宽比原图宽  比值，最大应该是1
                        jpgInfo.setDesRoundImgInfo(result1.getDesRoundImgInfo()); // A图框高比原图高  比值，最大应该是1
                        jpgInfo.setBadInBest1(result1.getBadInBest1()); // 坏线和总线比  乱线的根数，与总根数（乱线加保留线）的比值，比值越低越好。

//                        float[] aInFloats = ArrayUtils.toPrimitive(aInVector.toArray(new Float[0]), 0.0F);
//                        float[] bInFloats = ArrayUtils.toPrimitive(bInVector.toArray(new Float[0]), 0.0F);
                        jpgInfo.setInScore(FeatureComparison.cosineSim(aFloats, bFloats)); // A图框内图与B图框内图之间向量的相似度
                    }
                    jpgInfoMap.put(jpgList, jpgInfo);
                }
            });
            if (null != contentsComparisonKey) {
                redisUtil.saveObject(contentsComparisonKey, NumberUtil.div(present, alist.size(), 2));
            }
            present++;
        }
        return getJpgSortShow(alist, blist, jpgInfoMap, type);
    }

    /**
     * 目录对比
     *
     * @param alist 目录A
     * @param blist 目录B
     * @param uid   用户id
     * @param type  key or path
     * @return
     */
    public List<ContentsComparisonRes> comparisonSortWithLine(List<FileDetails> alist, List<FileDetails> blist, Integer uid, Integer ab, Integer level, String contentsComparisonKey, String routingKey) {
        Map<List<String>, JpgInfo> jpgInfoMap = new ConcurrentHashMap<>();
        List<Integer> ids = new ArrayList<>();
        for (FileDetails aFile : alist) {
            for (FileDetails bFile : blist) {
                if (!aFile.getId().equals(bFile.getId())) {
                    List<String> jpgList = new ArrayList<>();
                    jpgList.add(aFile.getId().toString());
                    jpgList.add(bFile.getId().toString());
                    Collections.sort(jpgList);
                    ResultQueue resultQueue = new ResultQueue().setAb(ab).setLevel(level).setImg1(aFile.getPath()).setImg2(bFile.getPath()).setBox1(aFile.getArray().toString()).setBox2(bFile.getArray().toString()).setComparisonKey(jpgList);
                    resultQueueService.save(resultQueue);
                    rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_TOPICS_INFORM, routingKey, resultQueue.getId().toString());
                    ids.add(resultQueue.getId());
                }
            }
        }

        while (true) {
            long count = resultQueueService.count(Wrappers.<ResultQueue>lambdaQuery().in(ResultQueue::getId, ids).ne(ResultQueue::getFlag, 0));
            if (null != contentsComparisonKey) {
                redisUtil.saveObject(contentsComparisonKey, NumberUtil.div(count, ids.size(), 2));
            }
            if (count == ids.size()) {
                break;
            } else {
                ThreadUtil.sleep(3000);
            }
        }

        List<ResultQueue> list = resultQueueService.list(Wrappers.<ResultQueue>lambdaQuery().in(ResultQueue::getId, ids).ne(ResultQueue::getFlag, 0));

        Map<List<String>, SortUtil.Result> map = list.stream().collect(Collectors.toMap(ResultQueue::getComparisonKey, ResultQueue::getResult, (a, b) -> a));


        for (FileDetails aFile : alist) {
            float[] aFloats = ArrayUtils.toPrimitive(aFile.getVector().toArray(new Float[0]), 0.0F);
            blist.forEach(bFile -> {
                if (!aFile.getId().equals(bFile.getId())) {
                    String pathOrgin = aFile.getPath();
                    String pathTarget = bFile.getPath();
                    List<String> jpgList = new ArrayList<>();
                    JpgInfo jpgInfo = new JpgInfo();
                    jpgList.add(aFile.getId().toString());
                    jpgInfo.setAJpg(aFile.getPath());
                    jpgList.add(bFile.getId().toString());
                    jpgInfo.setBJpg(bFile.getPath());
                    jpgInfo.setAIsWhite(aFile.getIsWhite());
                    jpgInfo.setBIsWhite(bFile.getIsWhite());
                    jpgInfo.setAVector(aFile.getVector());
                    jpgInfo.setBVector(bFile.getVector());
                    jpgInfo.setHasPic(false);
                    Collections.sort(jpgList);

                    SortUtil.Result result = map.get(jpgList);
                    float[] bFloats = ArrayUtils.toPrimitive(bFile.getVector().toArray(new Float[0]), 0.0F);
                    jpgInfo.setScore(FeatureComparison.cosineSim(aFloats, bFloats)); // A图框内图与B图框内图之间向量的相似度
                    if (result.getAllResult()) {

//                            String oPath = tempPath + RandomUtil.randomString(6) + ".png";
//                            String tPath = tempPath + RandomUtil.randomString(6) + ".png";
//
//
//                            SortUtil.RoundPoint sourceRoundPint = result1.getSourceRoundPint();
//                            SortUtil.RoundPoint desRoundPint = result1.getDesRoundPint();
//
//                            ImgUtil.cut(ImgUtil.read(new ByteArrayInputStream(minioUtil.downloadByte(pathOrgin))), new File(oPath), new Rectangle(sourceRoundPint.getMinX(), sourceRoundPint.getMinY(), sourceRoundPint.getMaxX() - sourceRoundPint.getMinX(), sourceRoundPint.getMaxY() - sourceRoundPint.getMinY()));
//                            ImgUtil.cut(ImgUtil.read(new ByteArrayInputStream(minioUtil.downloadByte(pathTarget))), new File(tPath), new Rectangle(desRoundPint.getMinX(), desRoundPint.getMinY(), desRoundPint.getMaxX() - desRoundPint.getMinX(), desRoundPint.getMaxY() - desRoundPint.getMinY()));
//                            oPath = minioUtil.upload(FileUtil.getInputStream(oPath), uid, DateUtil.today(), oPath.replace(tempPath, ""), Scenario.linepic);
//                            tPath = minioUtil.upload(FileUtil.getInputStream(tPath), uid, DateUtil.today(), tPath.replace(tempPath, ""), Scenario.linepic);
//
//                            List<Float> aInVector = featureService.imageFeature(oPath);
//                            List<Float> bInVector = featureService.imageFeature(tPath);
//
//                            FileUtil.del(oPath);
//                            FileUtil.del(tPath);
//                            minioUtil.remove(oPath);
//                            minioUtil.remove(tPath);

                        jpgInfo.setHasPic(true);
//                            jpgInfo.setAInVector(aInVector); // A图框内图的向量
//                            jpgInfo.setBInVector(bInVector); // B图框内图的向量

                        jpgInfo.setPicKey(result.getResultImg());
                        jpgInfo.setPic(result.getResultImg());
                        jpgInfo.setSourceRoundImgInfo(result.getSourceRoundImgInfo()); // A图框宽比原图宽  比值，最大应该是1
                        jpgInfo.setDesRoundImgInfo(result.getDesRoundImgInfo()); // A图框高比原图高  比值，最大应该是1
                        jpgInfo.setBadInBest1(result.getBadInBest1()); // 坏线和总线比  乱线的根数，与总根数（乱线加保留线）的比值，比值越低越好。

//                            float[] aInFloats = ArrayUtils.toPrimitive(aInVector.toArray(new Float[0]), 0.0F);
//                            float[] bInFloats = ArrayUtils.toPrimitive(bInVector.toArray(new Float[0]), 0.0F);
//                            jpgInfo.setInScore(FeatureComparison.cosineSim(aInFloats, bInFloats)); // A图框内图与B图框内图之间向量的相似度
                    }
                    jpgInfoMap.put(jpgList, jpgInfo);
                }
            });
        }

        return getJpgSortShow(alist, blist, jpgInfoMap, true);
    }

    public PictureWireVo pictureWire(String pathOrgin, String pathTarget) {

        /**
         * 最小连线数量
         */
        Integer minGoodPointNum = 10;
        /**
         * 连线总数的20%为最大值
         */
        Double singlePointPlace = 0.2;

        /**
         * 最大汉明距离
         */
        Double maxDistance = 200.0;

        /**
         * 原图目标图三角函数最小比例
         */
        Double sourceTargetLineMin = 0.8;

        /**
         * 原图目标图三角函数最大比例
         */
        Double sourceTargetLineMax = 1.2;

        /**
         * 是否使用图片等比
         */
        Boolean useProportion = true;

        /**
         * 是否显示结果
         */
        Boolean showResultImgForTest = true;

        /**
         * 是否划线
         */
        Boolean needLine = false;


        /**
         * 圈定原图目标图三角函数最小比例
         */
        Double sourceTargetRoundMin = 0.7;

        /**
         * 圈定原图目标图三角函数最小比例
         */
        Double sourceTargetRoundMax = 1.3;

        /**
         * 圈定区域宽高占总宽高最小比值
         */
        Double RoundSource = 0.1;

        /**
         * 无效线占总线的比例阈值
         */
        Double badInBestProportion = 0.6;


        Mat img1 = Imgcodecs.imdecode(new MatOfByte(minioUtil.downloadByte(pathOrgin)), 1);
        Mat img2 = Imgcodecs.imdecode(new MatOfByte(minioUtil.downloadByte(pathTarget)), 1);


        if (img1.empty() || img2.empty()) {
            return null;
        }

        Mat clone1 = new Mat();
        Mat clone2 = new Mat();
        img1.copyTo(clone1);
        img2.copyTo(clone2);

        Imgproc.GaussianBlur(clone1, clone1, new Size(3, 3), 0, 0);
        Imgproc.cvtColor(clone1, clone1, Imgproc.COLOR_BGR2GRAY);

        Imgproc.GaussianBlur(clone2, clone2, new Size(3, 3), 0, 0);
        Imgproc.cvtColor(clone2, clone2, Imgproc.COLOR_BGR2GRAY);


        Core.copyMakeBorder(img1, img1, 0, 0, 0, 5, Core.BORDER_CONSTANT, new Scalar(255, 255, 255));
        Imgproc.line(img1, new Point(img1.width() - 1, 0), new Point(img1.width() - 1, img1.height()), new Scalar(255, 255, 255), 5);

        MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
        MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
        Mat des1 = new Mat();
        Mat des2 = new Mat();
        SIFT sift = SIFT.create();
        sift.detectAndCompute(clone1, new Mat(), keypoints1, des1);
        sift.detectAndCompute(clone2, new Mat(), keypoints2, des2);


//            if (requestVo.getAlgorithm() == 2) {
//                SIFT sift
//                if (requestVo.getAlgorithmparam() == 1) {
//                    sift = SIFT.create(requestVo.getPointSize(), requestVo.getNoctavelayers());
//                } else {
//                    sift = SIFT.create();
//                }
//                sift.detectAndCompute(clone1, new Mat(), keypoints1, des1);
//                sift.detectAndCompute(clone2, new Mat(), keypoints2, des2);
//            } else {
//                SURF surf;
//                if (requestVo.getAlgorithmparam() == 1) {
//                    surf = SURF.create(requestVo.getHessianThreshold(), requestVo.getNoctaves(), requestVo.getNoctavelayers());
//                } else {
//                    surf = SURF.create();
//                }
//                surf.detectAndCompute(clone1, new Mat(), keypoints1, des1);
//                surf.detectAndCompute(clone2, new Mat(), keypoints2, des2);
//            }

        if (des1.empty() || des2.empty()) {
            return null;
        }

        MatOfDMatch md = new MatOfDMatch();
        FlannBasedMatcher matcher = FlannBasedMatcher.create();
        matcher.match(des1, des2, md);

        double maxDist = 0;
        double minDist = 1000;
        DMatch[] mats = md.toArray();

        List<DMatch> bestMatches = new ArrayList<>();
        for (int i = 0; i < mats.length; i++) {
            double dist = mats[i].distance;
            if (dist < minDist) {
                minDist = dist;
            }
            if (dist > maxDist) {
                maxDist = dist;
            }
        }
        double threshold = 3 * minDist;
        double threshold2 = 2 * minDist;
        if (threshold2 >= maxDist) {
            threshold = minDist * 1.1;
        } else if (threshold >= maxDist) {
            threshold = threshold2 * 1.4;
        }
        if (0d == threshold) {
            threshold = 0.3 * maxDist;
        }

        MatOfDMatch match = new MatOfDMatch();
        Double num = 0.0;
        for (int i = 0; i < mats.length; i++) {
            Double dist = (double) mats[i].distance;
            if (dist <= threshold && mats[i].distance < maxDistance) {
                num++;
                bestMatches.add(mats[i]);
            }
        }

        List<KeyPoint> keyPoints1 = keypoints1.toList();
        List<KeyPoint> keyPoints2 = keypoints2.toList();

        List<PointDMatch> xPointList = new ArrayList<>();

        for (int i = 0; i < bestMatches.size(); i++) {
            DMatch dMatch = bestMatches.get(i);
            KeyPoint keyPoint = keyPoints1.get(bestMatches.get(i).queryIdx);
            PointDMatch xPointDMatch = new PointDMatch();
            xPointDMatch.setPoint(keyPoint.pt.x);
            xPointDMatch.setDMatch(dMatch);
            xPointList.add(xPointDMatch);
        }

        List<PointDMatch> xPointListSort = xPointList.stream().sorted(Comparator.comparing(PointDMatch::getPoint)).collect(Collectors.toList());

        /**
         * 坏点
         */
        Set<DMatch> badPoint = new HashSet<>();

        /**
         * 根据勾股定理判断本点与下一个本点 连点与下一个连点之间的距离，如果距离不符合就删掉本线
         */

        Double proportion1 = Convert.toDouble(img1.width()) / (img2.width());
        Double proportion2 = Convert.toDouble(img1.height()) / (img2.height());

        Double proportion = Math.abs(proportion1 - 1) > Math.abs(proportion2 - 1) ? proportion2 : proportion1;

        for (int i = 0; i < xPointListSort.size() - 1; i++) {

            KeyPoint keyPoint1 = keyPoints1.get(xPointListSort.get(i).getDMatch().queryIdx);
            KeyPoint keyPoint2 = keyPoints1.get(xPointListSort.get(i + 1).getDMatch().queryIdx);
            Double x1 = Math.abs(keyPoint2.pt.x - keyPoint1.pt.x);
            Double y1 = Math.abs(keyPoint2.pt.y - keyPoint1.pt.y);
            double line1 = Math.sqrt(Math.pow(x1, 2) + Math.pow(y1, 2));

            KeyPoint keyPoint3 = keyPoints2.get(xPointListSort.get(i).getDMatch().trainIdx);
            KeyPoint keyPoint4 = keyPoints2.get(xPointListSort.get(i + 1).getDMatch().trainIdx);
            Double x2 = Math.abs(keyPoint4.pt.x - keyPoint3.pt.x);
            Double y2 = Math.abs(keyPoint4.pt.y - keyPoint3.pt.y);
            double line2 = Math.sqrt(Math.pow(x2, 2) + Math.pow(y2, 2));

            Double line1min = line1 * sourceTargetLineMin;
            Double line1max = line1 * sourceTargetLineMax;

            if (line1 == 0 || line2 == 0 || ((line2 < line1min || line2 > line1max))) {
                if (useProportion) {
                    if (line2 * proportion < line1min || line2 * proportion > line1max) {
                        badPoint.add(xPointListSort.get(i).getDMatch());
                    }
                } else {
                    badPoint.add(xPointListSort.get(i).getDMatch());
                }
            } else {
            }
        }
        /**
         * 无效线占总连线的比例，如果大于某个值，就认为这两张图片不像，直接跳出。
         */
        Double badInBest = badPoint.size() / Convert.toDouble(bestMatches.size());
        if (badInBest > badInBestProportion) {
            return null;
        }

        /**
         * 过滤孤岛点
         */
        List<Double> differenceListX = new ArrayList<>();
        List<Double> differenceListY = new ArrayList<>();
        for (int i = 0; i < bestMatches.size() - 1; i++) {
            KeyPoint keyPoint1X = keyPoints1.get(bestMatches.get(i).queryIdx);
            KeyPoint keyPoint1Y = keyPoints1.get(bestMatches.get(i + 1).queryIdx);
            differenceListX.add(keyPoint1Y.pt.x - keyPoint1X.pt.x);
            differenceListY.add(keyPoint1Y.pt.y - keyPoint1X.pt.y);
        }

        Map<Double, DMatch> xDatchsMap = new HashMap<>();
        Map<Double, DMatch> yDatchsMap = new HashMap<>();
        for (DMatch bestMatch : bestMatches) {
            KeyPoint keyPoint = keyPoints1.get(bestMatch.queryIdx);
            xDatchsMap.put(keyPoint.pt.x, bestMatch);
            yDatchsMap.put(keyPoint.pt.y, bestMatch);
        }

        List<DMatch> xMatchsList = new ArrayList<>();
        xDatchsMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(x -> xMatchsList.add(x.getValue()));

        List<DMatch> yMatchsList = new ArrayList<>();
        yDatchsMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(x -> yMatchsList.add(x.getValue()));

        Collections.sort(differenceListX, Collections.reverseOrder());
        Collections.sort(differenceListY, Collections.reverseOrder());

        Integer idX = Convert.toInt(differenceListX.size() * singlePointPlace);
        Integer idY = Convert.toInt(differenceListY.size() * singlePointPlace);

        Double xNum = 0.0;
        Double yNum = 0.0;
        if (idX > 0) {
            xNum = differenceListX.get(idX - 1);
        }
        if (idY > 0) {
            yNum = differenceListY.get(idY - 1);
        }

        for (int i = 0; i < xMatchsList.size() - 1; i++) {
            KeyPoint keyPoint1X = keyPoints1.get(xMatchsList.get(i).queryIdx);
            KeyPoint keyPoint1Y = keyPoints1.get(xMatchsList.get(i + 1).queryIdx);
            if (keyPoint1Y.pt.x - keyPoint1X.pt.x > xNum) {
                badPoint.add(xMatchsList.get(i));
            }
        }

        for (int i = 0; i < yMatchsList.size() - 1; i++) {
            KeyPoint keyPoint1X = keyPoints1.get(yMatchsList.get(i).queryIdx);
            KeyPoint keyPoint1Y = keyPoints1.get(yMatchsList.get(i + 1).queryIdx);
            if (keyPoint1Y.pt.y - keyPoint1X.pt.y > yNum) {
                badPoint.add(yMatchsList.get(i));
            }
        }

        List<DMatch> goodPoint = new ArrayList<>();
        for (DMatch bestMatch : bestMatches) {
            if (!badPoint.contains(bestMatch)) {
                goodPoint.add(bestMatch);
            }
        }

        if (goodPoint.size() > minGoodPointNum) {
            Integer minX1 = 999999999;
            Integer minY1 = 999999999;
            Integer maxX1 = 0;
            Integer maxY1 = 0;

            Integer minX2 = 999999999;
            Integer minY2 = 999999999;
            Integer maxX2 = 0;
            Integer maxY2 = 0;

            for (DMatch bestMatch : goodPoint) {
                KeyPoint keyPoint1 = keyPoints1.get(bestMatch.queryIdx);
                if (keyPoint1.pt.x < minX1) {
                    minX1 = Convert.toInt(keyPoint1.pt.x);
                }

                if (keyPoint1.pt.y < minY1) {
                    minY1 = Convert.toInt(keyPoint1.pt.y);
                }

                if (keyPoint1.pt.x > maxX1) {
                    maxX1 = Convert.toInt(keyPoint1.pt.x);
                }

                if (keyPoint1.pt.y > maxY1) {
                    maxY1 = Convert.toInt(keyPoint1.pt.y);
                }


                KeyPoint keyPoint2 = keyPoints2.get(bestMatch.trainIdx);
                if (keyPoint2.pt.x < minX2) {
                    minX2 = Convert.toInt(keyPoint2.pt.x);
                }

                if (keyPoint2.pt.y < minY2) {
                    minY2 = Convert.toInt(keyPoint2.pt.y);
                }

                if (keyPoint2.pt.x > maxX2) {
                    maxX2 = Convert.toInt(keyPoint2.pt.x);
                }

                if (keyPoint2.pt.y > maxY2) {
                    maxY2 = Convert.toInt(keyPoint2.pt.y);
                }
            }

            Imgproc.line(img1, new Point(minX1, minY1), new Point(minX1, maxY1), new Scalar(0, 0, 255), 2);
            Imgproc.line(img1, new Point(minX1, minY1), new Point(maxX1, minY1), new Scalar(0, 0, 255), 2);
            Imgproc.line(img1, new Point(minX1, maxY1), new Point(maxX1, maxY1), new Scalar(0, 0, 255), 2);
            Imgproc.line(img1, new Point(maxX1, minY1), new Point(maxX1, maxY1), new Scalar(0, 0, 255), 2);

            Imgproc.line(img2, new Point(minX2, minY2), new Point(minX2, maxY2), new Scalar(0, 0, 255), 2);
            Imgproc.line(img2, new Point(minX2, minY2), new Point(maxX2, minY2), new Scalar(0, 0, 255), 2);
            Imgproc.line(img2, new Point(minX2, maxY2), new Point(maxX2, maxY2), new Scalar(0, 0, 255), 2);
            Imgproc.line(img2, new Point(maxX2, minY2), new Point(maxX2, maxY2), new Scalar(0, 0, 255), 2);

            if (needLine) {
                match.fromList(goodPoint);
            }

            if ((maxX1 - minX1) > img1.width() * RoundSource && (maxY1 - minY1) > img1.height() * RoundSource && (maxX2 - minX2) > img2.width() * RoundSource && (maxY2 - minY2) > img2.height() * RoundSource) {
                Double line1 = Math.sqrt(Math.pow((maxX1 - minX1), 2) + Math.pow((maxY1 - minY1), 2));
                Double line2 = Math.sqrt(Math.pow((maxX2 - minX2), 2) + Math.pow((maxY2 - minY2), 2));
                if (line1 * sourceTargetRoundMin < line2 && line1 * sourceTargetRoundMax > line2) {
                    Mat result = new Mat();
                    Features2d.drawMatches(img1, keypoints1, img2, keypoints2, match, result, Scalar.all(-1), Scalar.all(-1), new MatOfByte(), 2);
                    MatOfByte matOfByte = new MatOfByte();
                    Imgcodecs.imencode(".jpg", result, matOfByte);
                    byte[] bytes = matOfByte.toArray();
                    return new PictureWireVo().setPathOrgin(pathOrgin).setPathTarget(pathTarget).setPic(bytes).setOMinX(minX1).setOMinY(minY1).setOMaxX(maxX1).setOMaxY(maxY1).setTMinX(minX2).setTMinY(minY2).setTMaxX(maxX2).setTMaxY(maxY2);
                }
            }

            /**
             * 匹配成功，画图
             */

        } else {
            /**
             * 匹配失败
             */
        }


        return null;
    }

    public Boolean checkWhiteBlock(String filename) {

//        BufferedImage bi = ImgUtil.read(new ByteArrayInputStream(minioUtil.downloadByte(filename)));
//        int height = bi.getHeight();
//        int width = bi.getWidth();
//
//        Integer heightThreshold = Convert.toInt(height * 0.15);
//        Integer widthThreshold = Convert.toInt(width * 0.15);
//
//        for (int i = 0; i < height - heightThreshold; i++) {
//            for (int j = 0; j < width - widthThreshold; j++) {
//                Boolean whiteBlock = true;
//                T:
//                for (int s = j; s < j + widthThreshold; s++) {
//                    for (int t = i; t < i + heightThreshold; t++) {
//                        int rgb = bi.getRGB(s, t);
//                        Color color = ImgUtil.getColor(rgb);
//                        if (color.getRed() < 250 || color.getGreen() < 250 || color.getBlue() < 250) {
//                            whiteBlock = false;
//                            j = s;
//                            break T;
//                        }
//                    }
//                }
//                if (whiteBlock) {
//                    return true;
//                }
//            }
//        }
        return false;
    }

    @Data
    public static class ImgAndScore {
        private Integer id;
        private float score = (float) 0.0;
        private int state = 0; // 未曾展示过的为1，已经展示过的为0
    }

    @Data
    public static class PointDMatch {
        Double point;
        DMatch dMatch;
    }

    @Data
    @Accessors(chain = true)
    public static class OutputJpgInfo implements Serializable {
        private String jpg = ""; // 图片的路径，这里是指前端在下面显示的图
        private double score = 0.0; // 该图片与上面的图片之间的综合得分
        private int hasPic = 0;  // 两张图之间是否有连线，1是有连线
        private int isFirst = 0;  // 第一次显示为1，再次显示为0
    }


}
